//
// Created by denglibin on 19-10-17.
//
/**
 * 多进程拷贝
 */
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>

static int main_(int argc, char * argv[]){
    int p_num = 5; // 拷贝进程数
    char *src_file = "/home/denglibin/test/main"; // 源文件
    char *dest_file = "/home/denglibin/test/main_copy"; // 目标文件
    int src_fd = open(src_file, O_RDONLY, 0644); // 读模式
    if(src_fd < 0){
        perror("open:");
        return -1;
    }
    int dest_fd = open(dest_file, O_RDWR | O_CREAT | O_TRUNC, 0644); // 读写模式
    if(dest_fd < 0){
        perror("open:");
        return -1;
    }
    // 获取源文件的大小
    struct stat src_stat;
    if(fstat(src_fd, &src_stat) < 0){
        perror("fstat:");
        exit(-1);
    }
    __off_t src_size = src_stat.st_size; // 文件大小
    printf("file size: %d\n", src_size);
    if((ftruncate(dest_fd, src_size)) < 0 ){ // 把目标文件大小扩展为源文件的大小
        perror("ftruncate:");
        exit(-1);
    }
    // 源文件内存映射
    char *src_map = mmap(NULL, src_size, PROT_READ, MAP_SHARED, src_fd, 0);
    if(src_map == MAP_FAILED){
        perror("mmap:");
        exit(-1);
    }
    // 目标文件内存映射
    char *dest_map = mmap(NULL, src_size, PROT_WRITE, MAP_SHARED, dest_fd, 0);
    if(dest_map == MAP_FAILED){
        perror("mmap:");
        exit(-1);
    }
    if(src_size < p_num){
        p_num = src_size;
    }
    int per_size = src_size / p_num; //每个进程拷贝的数据大小
    int mod = src_size % p_num; // 剩余部分大小 交给最后一个进程处理
    int i;
    for( i= 0; i < p_num; i++){ // 创建进程
        if(fork() == 0){ // 子进程不能创建进程
            break;
        }
    }
    if(i == p_num){ // 表示是父进程
        while (i){ // 回收子进程
            int status = -1;
            int c_pid = wait(&status); // 回收子进程
            printf("child process %d completed status:%d\n", c_pid, status);
            i--;
        }
        munmap(dest_map, src_size);
        munmap(src_map, src_size);
        close(dest_fd);
        close(src_fd);
    } else if(i == p_num-1){ // 最后一子进程
        memcpy(dest_map + i * per_size, src_map + i * per_size, per_size + mod); // 拷贝函数 （目标地址，源地址，拷贝字节数）
    } else if(i == 0){ // 第一个子进程
        memcpy(dest_map, src_map, per_size);
    } else{ // 其他子进程
        memcpy(dest_map + i * per_size + 1, src_map + i * per_size + 1, per_size);
    }
    return 0;
}

